#/usr/bin/python27
#-*- coding: utf-8 -*-
#  Copyright 2011-2013 wuweihui@cn.ibm.com
#
#  Licensed under the Apache License, Version 2.0 (the "License");
#  you may not use this file except in compliance with the License.
#  You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS,
#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#  See the License for the specific language governing permissions and
#  limitations under the License.

import sys
import re
import random
from CIMConnection.CIMlib import *
#from comm.loglib import *

VOL_PREFIX = "TA"

class ReturnCodeError(RuntimeError):
   pass

def generate_vol_prefix():
   global VOL_PREFIX
   VOL_PREFIX = "TA" + chr(random.randint(65, 90)) + chr(random.randint(65, 90))
   vollist = ms_enumerate('MSFT_SMStorageVolume', VOL_PREFIX)
   count = 0
   while vollist:
      vollist = ms_enumerate('MSFT_SMStorageVolume', VOL_PREFIX)
      count += 1
      if count > 20:
         break
   if vollist:
      raise RuntimeError("Can not find appropriate volume prefix in 20 times!")
   return VOL_PREFIX


def get_pool_sizes():
   """
   1. Enumerate MSFT_SMPool
   2. return pool size and size division list
   """
   poollist = ms_enumerate("MSFT_SMPool", filter='all')
   i = len(poollist)
   while i > 0:
      i -= 1
      pool = poollist[i]
      if not pool.__hasattr__('RemainingManagedSpace') or pool.Primordial == "true":
         poollist.remove(pool)
   poollist.sort(cmp=lambda x,y: cmp(x.RemainingManagedSpace, y.RemainingManagedSpace), reverse=True)
   if not poollist:
      raise RuntimeError("No pool information found on the storage!")
   return poollist

def get_pool_size_division(pool):
   poolsizeinfo = ms_get_sizes_info(pool)
   return str(min(int(poolsizeinfo.MinimumVolumeSize), int(poolsizeinfo.VolumeSizeDivisor)))

VOL_ID = '000'
def gen_vol_id():
   global VOL_ID
   VOL_ID = str(int(VOL_ID) + 1).zfill(3)
   return VOL_ID

def check_volume_in_system(volname):
   """
   check volume by volume name,
   return MS_VOL/False, msg
   """
   
   ibm_vol_list = ms_cim_enumerate("CIM_StorageVolume", volname)
   if not ibm_vol_list:
      return False, "Volume not found on storage!"
   for vol in ibm_vol_list:
      if vol.ElementName == volname:
         break
   if vol.ElementName != volname:
      return False, "Volume not found on storage!"
      
   ms_vol_list = ms_enumerate("MSFT_SMStorageVolume", volname)
   if not ms_vol_list:
      return False, "Volume not found in SMS service!"
   for vol in ms_vol_list:
      if vol.DisplayName == volname:
         break
   if vol.DisplayName != volname:
      return False, "Volume not found in SMS service!"   
    
   return vol, 'Volume found in system!'
   
def ms_get_vol(k, v):
   """
   Get volume instance by key and value
   """
      
   ms_vol_list = ms_enumerate("MSFT_SMStorageVolume", v)
   vollist = ms_vol_list.GetItemList(k, v)
   if not vollist:
      return None
   return vollist[0]

def ms_create_vol(pool=None, volname=None, size=None, nsf=None, 
                  pd=None, dd=None, pl=None, system=None):
   """
   cpsv or createPoolStorageVolume <srcPool-objID> <elementName> <new-size-in-bytes> 
       <nosinglepointoffailure(0=false,1=true)> <packageredundancygoal> <dataredundancygoal> 
       <paritylayout> [[user name] [pwd|!]]
   cssv or createSystemStorageVolume <system-objID><elementName>
       <new-size-in-bytes><nosinglepointoffailure(0=false,1=true)>
       <packageredundancygoal><dataredundancygoal><paritylayout> [[user name] [pwd|!]]
       
   Use dictionary parameters to call this function to avoid confusion
   volname is a mandartory input, others are optional
   return added volume instance
   """
   if pool:
      cmd = "createPoolStorageVolume"
      objid = pool.ObjectId
   elif system:
      cmd = "createSystemStorageVolume"
      objid = system.ObjectId
      pool = get_pool_sizes()[0]
   else:
      cmd = "createPoolStorageVolume"
      pool = get_pool_sizes()[0]
      objid = pool.ObjectId
   size = size or get_pool_size_division(pool)
   nsf = nsf or "true"
   pd = pd or "1"
   dd = dd or "2"
   pl = pl or ''
   ret = exec_ms_cmd_ex(cmd, objid, volname, size, nsf, pd, dd, pl)
   if ret.ReturnValue != '0':
      raise ReturnCodeError("Volume Creation Failure! Return code not right!")
   vol = ms_get_vol("DisplayName", volname)
   if not vol:
      raise RuntimeError("Volume Can not found in SMS service!")
   return vol
   
def ms_remove_vol(vol):
   """
   dsv or deleteStorageVolume <stgVolume-objID|stgVolume-ref|stgVolume-name> [[user name] [pwd|!]]
   """
   if not isinstance(vol, basestring):
      vol = vol.Name
   ret = exec_ms_cmd_ex('deleteStorageVolume', vol)
   if ret.ReturnValue != '0':
      raise ReturnCodeError("Volume Delete Failure! Return code not right!")
   
def get_volume_size(msvol):
   return long(msvol.BlockSize) * long(msvol.NumberOfBlocks)

def ms_create_spc(sysid=None, name=None, luns=None, dn=None, da=None, iid=None, tid=None, hostmode=None):
   """
   cssg or createSystemStorageGroup <system-objID> [Name] [LUNames] [DeviceNumbers] 
   [DeviceAccesses] [InitiatorID] [TargetPortID[Replace with TargetPortIDs?]] 
   [HostMode] [[user name] [pwd|!]]
   """
   
   if not isinstance(sysid, basestring):
      sysid = sysid.ObjectId
   name = name or ''
   luns = luns or ''
   if not isinstance(luns, basestring):
      luns = luns.Name
   dn = dn or '1'
   da = da or '2'
   iid = iid or ''
   tid = tid or ''
   hostmode = hostmode or ''
   
   cmd = 'createSystemStorageGroup'
   ret = exec_ms_cmd_ex(cmd, sysid, name, luns, dn, da, iid, tid, hostmode)
   if ret.ReturnValue not in ['0', '40045']:
      raise ReturnCodeError("SPC Creation Failure! Return code not right!")
   groupid = get_attr_from_value(ret.StorageGroup)['ObjectId']
   groups = ms_enumerate('MSFT_SMStorageGroup', groupid)
   if len(groups) != 1:
      raise RuntimeError("Storage group creation failed, not found in system!")
   return groups[0]

def ms_remove_spc(spcid):
   """
   deleteStorageGroup <storageGroup-ObjId>
   """
   if not isinstance(spcid, basestring):
      spcid = spcid.ObjectId
   cmd = "deleteStorageGroup"
   ret = exec_ms_cmd_ex(cmd, spcid)
   if ret.ReturnValue != '0':
      raise ReturnCodeError("SPC Delete Failure! Return code not right!")

def check_vol_in_spc(vol, spc):
   hwids = ms_enumerate('MSFT_SMStorageGroupToStorageHardwareID', spc.ObjectId)
   hwid = get_attr_from_value(hwid[0].Child)['ObjectId']
   stggrps = ms_stg_grp(hwid)
   if vol.Name in stggrps[0]:
      return True
   else:
      return False

if __name__ == '__main__':
   for poolsize in get_pool_sizes():
      print poolsize.RemainingManagedSpace